//=====================================================================
//
// 封装 KCP
//
//=====================================================================

#pragma once

#define USE_KCP

#ifdef USE_KCP

#include <thread>
#include <mutex>
#include "ikcp.h"

class CKcp
{
public:
	CKcp();
	~CKcp();
	CKcp(const CKcp& a);


	bool initialize(uint32_t devno, void* user, int mode, 
				int (*cb_output)(const char *buf, int len, ikcpcb *kcp, void *user),
				void (*cb_writelog)(const char *log, struct IKCPCB *kcp, void *user, int level));

	void uninitialize();

	int send(const char *buffer, int len);
	int recv();
	int input(const char *data, long size);

private:
	void update_thread();
	void print_infO() const;
	void reset();

#ifdef KCP_DEMO_CLOCK
	/* get system time */
	static inline void itimeofday(long *sec, long *usec)
	{
		#if defined(__unix)
		struct timeval time;
		gettimeofday(&time, NULL);
		if (sec) *sec = time.tv_sec;
		if (usec) *usec = time.tv_usec;
		#else
		static long mode = 0, addsec = 0;
		BOOL retval;
		static IINT64 freq = 1;
		IINT64 qpc;
		if (mode == 0) {
			retval = QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
			freq = (freq == 0)? 1 : freq;
			retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc);
			addsec = (long)time(NULL);
			addsec = addsec - (long)((qpc / freq) & 0x7fffffff);
			mode = 1;
		}
		retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc);
		retval = retval * 2;
		if (sec) *sec = (long)(qpc / freq) + addsec;
		if (usec) *usec = (long)((qpc % freq) * 1000000 / freq);
		#endif
	}

	/* get clock in millisecond 64 */
	static inline IINT64 iclock64(void)
	{
		long s, u;
		IINT64 value;
		itimeofday(&s, &u);
		value = ((IINT64)s) * 1000 + (u / 1000);
		return value;
	}

	static inline IUINT32 iclock()
	{
		return (IUINT32)(iclock64() & 0xfffffffful);
	}
#endif // KCP_DEMO_CLOCK


public:
	ikcpcb*				m_hkcp{NULL};
	enum{BUF_LEN=1024*4,};
	char 				buffer[BUF_LEN];

private:
	// 记录kcp参数，reset使用
	uint32_t			m_devno{0};
	int					m_mode{1};
	void* 				m_user{NULL};
	int 				(*m_output)(const char *buf, int len, struct IKCPCB *kcp, void *user){NULL};
	void 				(*m_writelog)(const char *log, struct IKCPCB *kcp, void *user, int level){NULL};


	std::thread*		m_hthread{NULL};
	bool				m_run{false};
	std::mutex			m_mutex;
};

#endif // USE_KCP
